技巧114 从镜像中提取文件

从镜像中复制文件使用 docker cp 命令很容易完成。但是不常见的情况下,可能你想从镜像中提取文件,但你没有运行干净的容器来进行复制。在这类情况下,可以人工运行一个该镜像的容器,执行 docker cp ,然后移除这一容器。这已经是3条命令了,然后可能会遇到问题,比如,镜像有一个需要传某种有意义的参数的默认入口点。

本技巧提供了一种单条命令的别名(alias),可放置在shell的启动脚本里来用一条命令两个参数来做这些事情。

问题

想要从镜像中复制文件到宿主机。

使用别名从带有入口点的镜像运行容器,用 cat 命令把某个文件的内容输出到宿主机上的文件中。

我们先展示如何构建一个 docker run 命令从该镜像中提取文件,然后展示如何从方便的角度把它转换成一个别名,如代码清单16-4所示。

代码清单16-4 使用docker run从镜像中提取文件

$ docker run --rm \  ⇽--- 使用--rm标志在执行此命令后立刻删除容器
 -i \  ⇽--- 使用-i标志来让容器可互动
 -t \  ⇽--- 使用-t标志来给容器一个可写入的虚拟终端
  --entrypoint=cat \  ⇽--- 把容器的入口文件设置为cat
 ubuntu \  ⇽--- 你想要从中提取文件的镜像的名字
 /etc/os-release \  ⇽--- 要输出的文件名
 > ubuntu_os-release  ⇽--- 把文件内容重定向到宿主机上的本地文件
$ cat ubuntu_os-release
NAME="Ubuntu"
VERSION="16.04.1 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.1 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
$ cat /etc/os-release  ⇽--- 为了强调这一点,展示/etc/os- release在宿主机上不存在
 cat: /etc/os-release: No such file or directory

读者可能会有疑问,为何这里要用 entrypoint ,而不是简单执行 cat 命令来输出文件。这是因为有些镜像可能已经设置了入口点。如果是这样,docker会把 cat 当作 entrypoint 命令的参数,导致不想要的后果。

方便起见,你可能想把这些命令设置为别名,如代码清单16-5所示。

代码清单16-5 使用别名来从镜像中提取文件

$ alias imagecat='docker run --rm -i -t --entrypoint=cat'  ⇽--- 把命令存为别名imagecat,包含清单16.4中的所有内容直到镜像和文件参数
$ imagecat ubuntu /etc/os-release  ⇽--- 使用两个参数来调用imagecat(镜像和文件名)
NAME="Ubuntu"
VERSION="16.04.1 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.1 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

讨论

本技巧假设容器中有 cat 命令。如果用技巧58来构建小型容器,可能就不是这种情况了,容器中只有你的二进制文件——没有标准Linux工具。

如果是这种情况,那么可以考虑使用技巧73中的 docker export 命令,但是与其把它们发送到其他机器,不如你只是从其中提取想要的文件。记住,容器不一定要成功启动了你才能把它公开出来——你可以尝试用容器中不存在的命令来运行,然后公开停止运行的容器(或者直接使用 docker create 命令,它会将容器准备好运行但不进行启动)。

results matching ""

    No results matching ""